﻿/* Project: LINQtoLDAPDemo_Setup
 * Purpose: To set up the LDAP objects used in LINQtoLDAPDemo_Winform
 * 
 * Requirements:
 * - AD LDS (http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=14683)
 * - An LDAP partition (http://community.bartdesmet.net/blogs/bart/archive/2010/07/12/getting-started-with-active-directory-lightweight-directory-services.aspx)
 * - Northwind database (http://northwinddatabase.codeplex.com/)
 * 
 * Reminders:
 * Update the app.config with:
 *  - Your computer name
 *  - The LDAP partition name
 *  - The database connection string to the Northwind database
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LINQtoLDAPDemo_Model;
using LinqToLdap;
using System.Configuration;

namespace LINQtoLDAPDemo_Setup
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                SetupLDAPConfig();

                CreateContainers();

                PopulateUserData();

                PopulateGroups();

                Console.WriteLine(string.Format("Populating test data to {0} was successful!", ConfigurationSettings.AppSettings["ldapPartition"]));
            }
            catch (Exception e)
            {
                Console.WriteLine(string.Format("Error: {0}", e.Message));
                Console.WriteLine(string.Format("Populating test data to {0} failed!", ConfigurationSettings.AppSettings["ldapPartition"]));
            }

            Console.Write("Press any key to continue...");
            Console.ReadKey();
        }

        private static void SetupLDAPConfig()
        {
            LdapConfiguration config = new LdapConfiguration();
            config.ConfigureFactory(ConfigurationSettings.AppSettings["computerName"]);
            config.AddMapping(new ContainerMapping());
            config.AddMapping(new UserMapping());
            config.AddMapping(new GroupMapping());
            config.UseStaticStorage();
        }

        private static void CreateContainers()
        {
            Container userFolder = new Container() { CN = "Users" };
            Container groupFolder = new Container() { CN = "Groups" };

            using (var ldapContext = new DirectoryContext())
            {
                if(ldapContext.Query<Container>().Count(x => x.CN.Equals(userFolder.CN)) == 0)
                    ldapContext.Add<Container>(userFolder);

                if (ldapContext.Query<Container>().Count(x => x.CN.Equals(groupFolder.CN)) == 0)
                    ldapContext.Add<Container>(groupFolder);
            }
        }

        private static void PopulateUserData()
        {
            CheckDBEmployeeData();

            using (var ldapContext = new DirectoryContext())
            {
                using (var ctx = new NorthwindDataContext())
                {
                    foreach (Employee e in ctx.Employees)
                    {
                        if (ldapContext.Query<User>().SingleOrDefault(ldapEntry => ldapEntry.EmployeeID == e.EmployeeID) == null)
                        {
                            int numOfEmployeesInLDAPWithSameName = ldapContext.Query<User>().Count(ldapEntry => ldapEntry.DisplayName.Equals(string.Format("{0} {1}", e.FirstName, e.LastName)));
                            if (numOfEmployeesInLDAPWithSameName > 0)
                            {
                                e.LastName = string.Format("{0}_{1}", e.LastName, numOfEmployeesInLDAPWithSameName);
                            }

                            ldapContext.Add<User>(e.ToUser());
                        }
                    }
                }
            }

            SetManagerValues();
        }

        private static void CheckDBEmployeeData()
        {
            int originalDBEmployeeCount = 9;

            using (var ctx = new NorthwindDataContext())
            {
                int currentDBEmployeeCount = ctx.Employees.Count();

                if (currentDBEmployeeCount <= originalDBEmployeeCount)
                {
                    ExcelTestData.EmployeeImporter importer = new ExcelTestData.EmployeeImporter();
                    Employee[] importedEmployees = importer.GetEmployeesFromExcel();

                    ctx.Employees.InsertAllOnSubmit(importedEmployees);

                    ctx.SubmitChanges();
                }
            }
        }
 
        // Because the DN for the manager employee must exist before setting it, we will set it up after the data is populated
        private static void SetManagerValues()
        {
            using (var ldapContext = new LinqToLdap.DirectoryContext())
            {
                using (var dbContext = new NorthwindDataContext())
                {
                    try
                    {
                        foreach (Employee e in dbContext.Employees)
                        {
                            User currentEmployee = ldapContext.Query<User>().SingleOrDefault(ldapEntry => ldapEntry.EmployeeID == e.EmployeeID);

                            // If employee exists in LDAP
                            if (currentEmployee != null)
                            {
                                // If employee's manager is specified
                                if (e.ReportsTo != null)
                                {
                                    User manager = ldapContext.Query<User>().SingleOrDefault(ldapEntry => ldapEntry.EmployeeID == e.ReportsTo);

                                    currentEmployee.Manager = manager.DistinguishedName;
                                    ldapContext.Update<User>(currentEmployee);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception();
                    }
                }
            }
        }

        private static void PopulateGroups()
        {
            using (var ldapContext = new DirectoryContext())
            {
                // Create groups
                Group employeeGroup = new Group() { Name = "Employee", Description = "All Northwind employees" };
                Group managerGroup = new Group() { Name = "Manager", Description = "All Northwind managers" };

                // Add groups to LDAP
                if(ldapContext.Query<Group>().Count(ldapGroup => ldapGroup.Name.Equals(employeeGroup.Name)) == 0)
                    ldapContext.Add<Group>(employeeGroup);

                if (ldapContext.Query<Group>().Count(ldapGroup => ldapGroup.Name.Equals(managerGroup.Name)) == 0)
                    ldapContext.Add<Group>(managerGroup);

                // Employee group members
                string[] employeeDNs = ldapContext.Query<User>().Select(ldapEntry => ldapEntry).ToArray().Select(e => e.DistinguishedName).ToArray();
                employeeGroup.Members = employeeDNs;

                // Manager group members
                string[] managerDNs = ldapContext.Query<User>().Where(ldapEntry => ldapEntry.Manager != null).Select(ldapEntry => ldapEntry.Manager).ToArray().Distinct().ToArray();
                managerGroup.Members = managerDNs;

                // Update groups with changes
                ldapContext.Update<Group>(employeeGroup);
                ldapContext.Update<Group>(managerGroup);
            }
        }
    }
}
